
// <copyright file="AbstractDbTableSync.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The abstract db table sync.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Data.Sync
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Threading.Tasks;

    /// <summary>
    /// The abstract db table sync.
    /// </summary>
    public abstract class AbstractDbTableSync : AbstractDisposable
    {
        #region Public Properties

        /// <summary>
        /// Gets the exception.
        /// </summary>
        public Exception Exception { get; private set; }

        #endregion Public Properties

        #region Methods

        /// <summary>
        /// The get comparer.
        /// </summary>
        /// <returns>
        /// The <see cref="IComparer"/>.
        /// </returns>
        protected abstract IComparer<IDataRecord> getComparer();

        /// <summary>
        /// The get data from source.
        /// </summary>
        /// <param name="sourceNumber">
        /// The source number.
        /// </param>
        /// <returns>
        /// The <see cref="IDataReader"/>.
        /// </returns>
        protected abstract IDataReader getDataFromSource(int sourceNumber);

        /// <summary>
        /// The perform post sync of matched records.
        /// </summary>
        /// <param name="sourceNumber">
        /// The source number.
        /// </param>
        protected virtual void performPostSyncOfMatchedRecords(int sourceNumber)
        {
        }

        /// <summary>
        /// The perform post sync of mismatched records.
        /// </summary>
        /// <param name="sourceNumber">
        /// The source number.
        /// </param>
        protected virtual void performPostSyncOfMismatchedRecords(int sourceNumber)
        {
        }

        /// <summary>
        /// The perform synchronization.
        /// </summary>
        /// <param name="options">
        /// The options.
        /// </param>
        /// <param name="directions">
        /// The directions.
        /// </param>
        protected void PerformSynchronization(SyncOptions options, SyncDirections directions)
        {
            IDataReader reader1 = this.getDataFromSource(1);
            IDataReader reader2 = this.getDataFromSource(2);
            IComparer<IDataRecord> comparer = this.getComparer();
            var sync = new DataReaderSync(reader1, reader2, comparer, options, directions);
            if (sync.ReaderForMissedRecordsInSource1 != null)
            {
                this.performSyncAsync(sync.ReaderForMissedRecordsInSource1, 1, true);
            }

            if (sync.ReaderForMissedRecordsInSource2 != null)
            {
                this.performSyncAsync(sync.ReaderForMissedRecordsInSource2, 2, true);
            }

            if (sync.ReaderForMatchedRecordsInSource1 != null)
            {
                this.performSyncAsync(sync.ReaderForMatchedRecordsInSource1, 2, false);
            }

            if (sync.ReaderForMatchedRecordsInSource2 != null)
            {
                this.performSyncAsync(sync.ReaderForMatchedRecordsInSource2, 1, false);
            }

            try
            {
                sync.StartSync();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());

                // terminateOnException(ex);
            }

            // _thread1.Join();
            // if (_connection1 != null)
            // {
            // _connection1.Close();
            // }
            // if (!_mergeOnlyOneSide)
            // {
            // _thread2.Join();
            // }
            // if (_connection2 != null)
            // {
            // _connection2.Close();
            // }
        }

        /// <summary>
        /// The start write operation into source for matched records.
        /// </summary>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="sourceNumber">
        /// The source number.
        /// </param>
        protected virtual void startWriteOperationIntoSourceForMatchedRecords(IDataReader reader, int sourceNumber)
        {
            while (reader.Read())
            {
            }
        }

        /// <summary>
        /// The start write operation into source for missed records.
        /// </summary>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="sourceNumber">
        /// The source number.
        /// </param>
        protected virtual void startWriteOperationIntoSourceForMissedRecords(IDataReader reader, int sourceNumber)
        {
            while (reader.Read())
            {
            }
        }

        /// <summary>
        /// The perform sync async.
        /// </summary>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="sourceNumber">
        /// The source number.
        /// </param>
        /// <param name="forMissedRecords">
        /// The for missed records.
        /// </param>
        private void performSyncAsync(IDataReader reader, int sourceNumber, bool forMissedRecords)
        {
            Task.Factory.StartNew(delegate
                {
                    if (forMissedRecords)
                    {
                        this.startWriteOperationIntoSourceForMissedRecords(reader, sourceNumber);
                    }
                    else
                    {
                        this.startWriteOperationIntoSourceForMatchedRecords(reader, sourceNumber);
                    }

                    if (forMissedRecords)
                    {
                        this.performPostSyncOfMismatchedRecords(sourceNumber);
                    }
                    else
                    {
                        this.performPostSyncOfMatchedRecords(sourceNumber);
                    }
                });
        }

        #endregion Methods
    }
}